package com.mt.sdk.ble.base;

import java.util.Locale;
import java.util.UUID;
import com.mt.sdk.ble.MTBLEDevice;
import com.mt.sdk.ble.MTBLEManager;
import com.mt.sdk.ble.model.BLEBaseAction;
import com.mt.sdk.ble.model.ErroCode;
import com.mt.sdk.ble.model.MTBeaconInfModel;
import com.mt.sdk.ble.model.ReadCharactAction;
import com.mt.sdk.ble.model.WriteCharactAction;
import com.mt.sdk.ble.model.WriteCharactWithAckAction;
import com.mt.sdk.ble.model.WriteDescriptorAction;
import com.mt.sdk.ble.model.BLEBaseAction.Option;
import com.mt.sdk.tools.MTTools;
import android.annotation.TargetApi;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import android.os.Build;
import android.os.Handler;

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public class MTBeacon123Base extends BLEBase {
	private Handler handl = new Handler();

	private MTBLEDevice device;
	private String pwd;
	public static String[] SENDPOWERNAME = new String[] { "A", "B", "C" };
	// 连接
	public ErroCode connect(MTBLEDevice device, String pwd, int retryTimes, boolean isScan, CallBack callback) {
		this.callback = callback;
		this.device = device;
		this.pwd = pwd;
		return super.connect(device.getDevice().getAddress(), retryTimes, isScan);
	}

	// 获取特定服务
	private static final String USER_SERVICE_UUID = "0000fae0-0000-1000-8000-00805f9b34fb";
	private static final String UUID_CHARACT_UUID = "0000fae1-0000-1000-8000-00805f9b34fb";
	private static final String MAJOR_CHARACT_UUID = "0000fae2-0000-1000-8000-00805f9b34fb";
	private static final String MINOR_CHARACT_UUID = "0000fae3-0000-1000-8000-00805f9b34fb";
	private static final String MEASURED_CHARACT_UUID = "0000fae4-0000-1000-8000-00805f9b34fb";
	private static final String ATCMD_CHARACT_UUID = "0000fae5-0000-1000-8000-00805f9b34fb";
	private BluetoothGattCharacteristic uuid_charact;
	private BluetoothGattCharacteristic major_charact;
	private BluetoothGattCharacteristic minor_charact;
	private BluetoothGattCharacteristic measured_charact;
	private BluetoothGattCharacteristic atcmd_charact;

	private boolean getCharacts() {
		BluetoothGattService data_service = getService(USER_SERVICE_UUID);
		if (data_service == null) { // 服务获取失败的情况
			return false;
		}

		uuid_charact = data_service.getCharacteristic(UUID.fromString(UUID_CHARACT_UUID));
		major_charact = data_service.getCharacteristic(UUID.fromString(MAJOR_CHARACT_UUID));
		minor_charact = data_service.getCharacteristic(UUID.fromString(MINOR_CHARACT_UUID));
		measured_charact = data_service.getCharacteristic(UUID.fromString(MEASURED_CHARACT_UUID));
		atcmd_charact = data_service.getCharacteristic(UUID.fromString(ATCMD_CHARACT_UUID));

		if ((uuid_charact == null) || (major_charact == null) || (minor_charact == null) || (measured_charact == null)
				|| (atcmd_charact == null)) {
			return false;
		}

		return true;
	}

	// 添加到监听列表
	private void addTolisten() {
		addListCharact(atcmd_charact);
	}

	// 使能特征值的可通知属性
	private boolean enableNotify() {
		addListCharact(atcmd_charact);
		enableNotify(atcmd_charact, true);
		BluetoothGattDescriptor descriptor = atcmd_charact
				.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
		descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
		addNewAction(new WriteDescriptorAction(descriptor, new BLEBaseAction.Option(2000)) {
			@Override
			public void onSuccess() {
				super.onSuccess();
				addTolisten();
				
				if(device.getSetlev() == 0){ // 可正常连接
					if (callback != null) {
						callback.onConnect(ErroCode.ERROMAP.get("OK"));
					}
					return;
				}
				
				if(device.getSetlev() == 1){  // 密码部署,需要密码验证
					System.out.println("密码部署,需要密码验证->"+pwd);
					String cmd = "AT+PWD["+pwd+"]";
					addNewAction(new WriteCharactWithAckAction(atcmd_charact, atcmd_charact, cmd.getBytes(),
							new Option(1000)) {

						@Override
						public void onReciveDatas(BluetoothGattCharacteristic characteristic, byte[] datas) {
							super.onReciveDatas(characteristic, datas);
							setStatues(ActionStatues.DONE);
							String ackcmd = new String(datas);
							System.out.println("ackcmd->"+ackcmd);
							if(!ackcmd.equals("OK+USER\r\n")){
								disConnect();
								if (callback != null) {
									callback.onConnect(ErroCode.ERROMAP.get("pwderro"));
								}
								return;
							}
							if (callback != null) {
								callback.onConnect(ErroCode.ERROMAP.get("OK"));
							}
						}

						@Override
						public void onFail(ErroCode erro) {
							super.onFail(erro);
							disConnect();
							System.out.println("onFail->" + erro.toString());
							if (callback != null) {
								callback.onConnect(ErroCode.ERROMAP.get("pwdfail"));
							}
						}

					});
					return;
				}
			}

			@Override
			public void onFail(ErroCode erro) {
				super.onFail(erro);
				if (callback != null) {
					callback.onConnect(ErroCode.ERROMAP.get("enablenotifyerro"));
				}
				disConnect();
			}

		});

		return true;
	}

	@Override
	final protected void onBaseConnect(ErroCode errocode) {
		super.onBaseConnect(errocode);
		if (errocode.getCode() != 0) { // 连接失败的情况
			if (callback != null) {
				callback.onConnect(errocode);
			}
			disConnect();
			return;
		}

		if (!getCharacts()) { // 获取特定服务失败的情况
			if (callback != null) {
				callback.onConnect(ErroCode.ERROMAP.get("getcharacterro"));
			}
			disConnect();
			return;
		}

		if (!enableNotify()) { // 使能可通知失败的情况
			System.out.println("enableNotify");
			disConnect();
			if (callback != null) {
				callback.onConnect(ErroCode.ERROMAP.get("enablenotifyerro"));
			}
			return;
		}
	}

	@Override
	final protected void reTryConnect(int lasttimes) {
		super.reTryConnect(lasttimes);
		if (callback != null) {
			callback.reTryConnect(lasttimes);
		}
	}

	@Override
	final protected void onDisConnect(ErroCode errocode) {
		super.onDisConnect(errocode);
		if (callback != null) {
			callback.onDisConnect(errocode);
		}
	}

	@Override
	final protected void onManualDisConnect(ErroCode errocode) {
		super.onManualDisConnect(errocode);
	}

	public MTBeacon123Base(Context context, MTBLEManager manager) {
		super(context, manager);
	}

	// 读取所有参数
	public boolean readAllInf(MTBLEDevice device, String pwd, final ReadInfsCallBack readinfscallback) {

		final MTBeaconInfModel deviceinf = new MTBeaconInfModel();

		ErroCode result = connect(device, pwd, 1, false, new CallBack() {

			@Override
			public void onConnect(ErroCode errocode) {
				if (errocode.getCode() != 0) {
					if (readinfscallback != null) {
						readinfscallback.onFail(errocode);
					}
					return;
				}

				addNewAction(new ReadCharactAction(uuid_charact, new Option(1000)) { // 读取UUID

					@Override
					public void onReadDatas(BluetoothGattCharacteristic characteristic, byte[] datas) {
						super.onReadDatas(characteristic, datas);
						if ((datas == null) || (datas.length < 16)) {
							return;
						}
						String uuid_str = MTTools.convertByteToString(datas[0])
								+ MTTools.convertByteToString(datas[1]) + MTTools.convertByteToString(datas[2])
								+ MTTools.convertByteToString(datas[3]) + "-"
								+ MTTools.convertByteToString(datas[4]) + MTTools.convertByteToString(datas[5])
								+ "-" + MTTools.convertByteToString(datas[6])
								+ MTTools.convertByteToString(datas[7]) + "-"
								+ MTTools.convertByteToString(datas[8]) + MTTools.convertByteToString(datas[9])
								+ "-" + MTTools.convertByteToString(datas[10])
								+ MTTools.convertByteToString(datas[11])
								+ MTTools.convertByteToString(datas[12])
								+ MTTools.convertByteToString(datas[13])
								+ MTTools.convertByteToString(datas[14])
								+ MTTools.convertByteToString(datas[15]);
						uuid_str = uuid_str.toUpperCase(Locale.getDefault());
						deviceinf.setBeaconUUID(uuid_str);
					}

					@Override
					public void onFail(ErroCode erro) {
						super.onFail(erro);
						disConnect();
						if (readinfscallback != null) {
							readinfscallback.onFail(ErroCode.ERROMAP.get("readuuiderro"));
						}
					}

					@Override
					public void onCancel() {
						super.onCancel();
					}

				});

				addNewAction(new ReadCharactAction(major_charact, new Option(1000)) { // 读取major

					@Override
					public void onReadDatas(BluetoothGattCharacteristic characteristic, byte[] datas) {
						super.onReadDatas(characteristic, datas);
						if((datas == null) || (datas.length != 2)){
							return;
						}
						int major_int = MTTools.convertUint16(datas[1], datas[0]);
						deviceinf.setMajor(major_int);
					}

					@Override
					public void onFail(ErroCode erro) {
						super.onFail(erro);
						disConnect();
						if (readinfscallback != null) {
							readinfscallback.onFail(ErroCode.ERROMAP.get("readmajorerro"));
						}
					}

					@Override
					public void onCancel() {
						super.onCancel();
					}

				});

				addNewAction(new ReadCharactAction(minor_charact, new Option(1000)) { // 读取minor

					@Override
					public void onFail(ErroCode erro) {
						super.onFail(erro);
						disConnect();
						if (readinfscallback != null) {
							readinfscallback.onFail(ErroCode.ERROMAP.get("readminorerro"));
						}
					}

					@Override
					public void onCancel() {
						super.onCancel();
					}
					@Override
					public void onReadDatas(BluetoothGattCharacteristic characteristic, byte[] datas) {
						super.onReadDatas(characteristic, datas);
						if((datas == null) || (datas.length != 2)){
							return;
						}
						int minor_int = MTTools.convertUint16(datas[1], datas[0]);
						deviceinf.setMinor(minor_int);
					}
				});

				addNewAction(new ReadCharactAction(measured_charact, new Option(1000)) { // 读取measured

					@Override
					public void onFail(ErroCode erro) {
						super.onFail(erro);
						disConnect();
						if (readinfscallback != null) {
							readinfscallback.onFail(ErroCode.ERROMAP.get("readmeasurederro"));
						}
					}

					@Override
					public void onCancel() {
						super.onCancel();
					}
					@Override
					public void onReadDatas(BluetoothGattCharacteristic characteristic, byte[] datas) {
						super.onReadDatas(characteristic, datas);
						if((datas == null) || (datas.length != 1)){
							return;
						}
						deviceinf.setMeasuedPower(Math.abs(datas[0]));
					}
				});

				addNewAction(new WriteCharactWithAckAction(atcmd_charact, atcmd_charact, "AT+POWE?".getBytes(),
						new Option(1000)) {

					@Override
					public void onReciveDatas(BluetoothGattCharacteristic characteristic, byte[] datas) {
						super.onReciveDatas(characteristic, datas);
						setStatues(ActionStatues.DONE);
						int sendpower = datas[7] - 'A';
						System.out.println("AT+POWE?->"+new String(datas)+", sendpower->"+sendpower);
						deviceinf.setSendpower(sendpower);
					}

					@Override
					public void onSuccess() {
						super.onSuccess();
					}

					@Override
					public void onFail(ErroCode erro) {
						super.onFail(erro);
						disConnect();
						if (readinfscallback != null) {
							readinfscallback.onFail(ErroCode.ERROMAP.get("readsendpowerderro"));
						}
					}
				});
				addNewAction(new WriteCharactWithAckAction(atcmd_charact, atcmd_charact, "AT+ADVI?".getBytes(),
						new Option(1000)) {

					@Override
					public void onReciveDatas(BluetoothGattCharacteristic characteristic, byte[] datas) {
						super.onReciveDatas(characteristic, datas);
						setStatues(ActionStatues.DONE);
						String str = new String(datas);
						str = str.substring(7, str.length() - 2);
						deviceinf.setSendhz(Integer.parseInt(str));
					}

					@Override
					public void onSuccess() {
						super.onSuccess();
						System.out.println("onSuccess");
					}

					@Override
					public void onFail(ErroCode erro) {
						super.onFail(erro);
						disConnect();
						if (readinfscallback != null) {
							readinfscallback.onFail(ErroCode.ERROMAP.get("readsendhzderro"));
						}
					}

				});
				addNewAction(new WriteCharactWithAckAction(atcmd_charact, atcmd_charact, "AT+VERS".getBytes(),
						new Option(1000)) {

					@Override
					public void onReciveDatas(BluetoothGattCharacteristic characteristic, byte[] datas) {
						super.onReciveDatas(characteristic, datas);
						setStatues(ActionStatues.DONE);
						deviceinf.setVersion(new String(datas));
						readinfscallback.onSuccess(new MTBeaconInfModel[] { deviceinf });
						disConnect();
					}

					@Override
					public void onSuccess() {
						super.onSuccess();
						System.out.println("onSuccess");
					}

					@Override
					public void onFail(ErroCode erro) {
						super.onFail(erro);
						disConnect();
						System.out.println("onFail->" + erro.toString());
						if (readinfscallback != null) {
							readinfscallback.onFail(ErroCode.ERROMAP.get("readversionderro"));
						}
					}

				});

			}

			@Override
			public void reTryConnect(int lasttimes) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onDisConnect(ErroCode errocode) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onManualDisConnect(ErroCode errocode) {

			}

			@Override
			public void onDatasRecive(BluetoothGattCharacteristic rxd_charact) {

			}
		});

		return (result.getCode() == 0);
	}

	// 设置通用参数major/minor/uuid
	public boolean setCommParamters(MTBLEDevice device, String pwd, final MTBeaconInfModel deviceinf,
			final BaseCallBack callback) {

		ErroCode result = connect(device, pwd, 1, false, new CallBack() {

			@Override
			public void onConnect(ErroCode errocode) {
				if (errocode.getCode() != 0) {
					if (callback != null) {
						callback.onFail(errocode);
					}
					return;
				}

				byte[] major_byte = new byte[] { MTTools.converLoUint16(deviceinf.getMajor()),
						MTTools.converHiUint16(deviceinf.getMajor()) };
				addNewAction(new WriteCharactAction(major_charact, major_byte, new Option(1000)) {

					@Override
					public void onSuccess() {
						super.onSuccess();
					}

					@Override
					public void onFail(ErroCode erro) {
						super.onFail(erro);
						disConnect();
						if (callback != null) {
							callback.onFail(ErroCode.ERROMAP.get("setmajorerro"));
						}
					}

				});

				byte[] minor_byte = new byte[] { MTTools.converLoUint16(deviceinf.getMinor()),
						MTTools.converHiUint16(deviceinf.getMinor()) };
				addNewAction(new WriteCharactAction(minor_charact, minor_byte, new Option(1000)) {

					@Override
					public void onSuccess() {
						super.onSuccess();
					}

					@Override
					public void onFail(ErroCode erro) {
						super.onFail(erro);
						disConnect();
						if (callback != null) {
							callback.onFail(ErroCode.ERROMAP.get("setminorerro"));
						}
					}

				});

				byte[] uuid_byte = MTTools.convertStringToByteArray(deviceinf.getBeaconUUID());
				addNewAction(new WriteCharactAction(uuid_charact, uuid_byte, new Option(1000)) {

					@Override
					public void onSuccess() {
						super.onSuccess();
						disConnect();
						if (callback != null) {
							callback.onSuccess();
						}
					}

					@Override
					public void onFail(ErroCode erro) {
						super.onFail(erro);
						disConnect();
						if (callback != null) {
							callback.onFail(ErroCode.ERROMAP.get("setuuiderro"));
						}
					}

				});

			}

			@Override
			public void reTryConnect(int lasttimes) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onDisConnect(ErroCode errocode) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onManualDisConnect(ErroCode errocode) {

			}

			@Override
			public void onDatasRecive(BluetoothGattCharacteristic rxd_charact) {

			}
		});

		return (result.getCode() == 0);
	}

	// 设置所有参数
	public boolean setAllParamters(MTBLEDevice device, String pwd, final MTBeaconInfModel deviceinf,
			final BaseCallBack callback) {

		ErroCode result = connect(device, pwd, 1, false, new CallBack() {

			@Override
			public void onConnect(ErroCode errocode) {
				if (errocode.getCode() != 0) {
					if (callback != null) {
						callback.onFail(errocode);
					}
					return;
				}
				byte[] major_byte = new byte[] { MTTools.converLoUint16(deviceinf.getMajor()),
						MTTools.converHiUint16(deviceinf.getMajor()) };
				addNewAction(new WriteCharactAction(major_charact, major_byte, new Option(1000)) {

					@Override
					public void onSuccess() {
						super.onSuccess();
					}

					@Override
					public void onFail(ErroCode erro) {
						super.onFail(erro);
						disConnect();
						if (callback != null) {
							callback.onFail(ErroCode.ERROMAP.get("setmajorerro"));
						}
					}

				});

				byte[] minor_byte = new byte[] { MTTools.converLoUint16(deviceinf.getMinor()),
						MTTools.converHiUint16(deviceinf.getMinor()) };
				addNewAction(new WriteCharactAction(minor_charact, minor_byte, new Option(1000)) {

					@Override
					public void onSuccess() {
						super.onSuccess();
					}

					@Override
					public void onFail(ErroCode erro) {
						super.onFail(erro);
						disConnect();
						if (callback != null) {
							callback.onFail(ErroCode.ERROMAP.get("setminorerro"));
						}
					}

				});

				byte[] uuid_byte = MTTools.convertStringToByteArray(deviceinf.getBeaconUUID());
				addNewAction(new WriteCharactAction(uuid_charact, uuid_byte, new Option(1000)) {

					@Override
					public void onSuccess() {
						super.onSuccess();
					}

					@Override
					public void onFail(ErroCode erro) {
						super.onFail(erro);
						disConnect();
						if (callback != null) {
							callback.onFail(ErroCode.ERROMAP.get("setuuiderro"));
						}
					}

				});

				byte[] measured_byte = new byte[] { (byte) -Math.abs(deviceinf.getMeasuedPower()) };
				addNewAction(new WriteCharactAction(measured_charact, measured_byte, new Option(1000)) {

					@Override
					public void onSuccess() {
						super.onSuccess();
					}

					@Override
					public void onFail(ErroCode erro) {
						super.onFail(erro);
						disConnect();
						if (callback != null) {
							callback.onFail(ErroCode.ERROMAP.get("setuuiderro"));
						}
					}

				});

				String sendpowercmd = "AT+POWE[" + SENDPOWERNAME[deviceinf.getSendpower()] + "]";
				addNewAction(
						new WriteCharactWithAckAction(atcmd_charact, atcmd_charact, sendpowercmd.getBytes(), new Option(1000)) {

					@Override
					public void onReciveDatas(BluetoothGattCharacteristic characteristic, byte[] datas) {
						super.onReciveDatas(characteristic, datas);
						setStatues(ActionStatues.DONE);
					}

					@Override
					public void onSuccess() {
						super.onSuccess();
					}

					@Override
					public void onFail(ErroCode erro) {
						super.onFail(erro);
						disConnect();
						if (callback != null) {
							callback.onFail(ErroCode.ERROMAP.get("readsendpowerderro"));
						}
					}
				});

				if(deviceinf.getNewpwd() != null){
					String newpwdcmd="";
					if(deviceinf.getNewpwd().length() == 0){
						System.out.println("取消密码");
						newpwdcmd = "AT+IBPWD";
					}else{
						System.out.println("设置密码->"+deviceinf.getNewpwd());
						newpwdcmd = "AT+IBPWD["+deviceinf.getNewpwd()+"]";
					}
					addNewAction(
							new WriteCharactWithAckAction(atcmd_charact, atcmd_charact, newpwdcmd.getBytes(), new Option(1000)) {

						@Override
						public void onReciveDatas(BluetoothGattCharacteristic characteristic, byte[] datas) {
							super.onReciveDatas(characteristic, datas);
							setStatues(ActionStatues.DONE);
						}

						@Override
						public void onSuccess() {
							super.onSuccess();
						}

						@Override
						public void onFail(ErroCode erro) {
							super.onFail(erro);
							disConnect();
							if (callback != null) {
								callback.onFail(ErroCode.ERROMAP.get("readsendpowerderro"));
							}
						}
					});
				}
				
				String sendhzcmd = "AT+ADVI[" + deviceinf.getSendhz() + "]";
				addNewAction(
						new WriteCharactWithAckAction(atcmd_charact, atcmd_charact, sendhzcmd.getBytes(), new Option(1000)) {

					@Override
					public void onReciveDatas(BluetoothGattCharacteristic characteristic, byte[] datas) {
						super.onReciveDatas(characteristic, datas);
						setStatues(ActionStatues.DONE);
						if (callback != null) {
							callback.onSuccess();
						}
						disConnect();
					}

					@Override
					public void onFail(ErroCode erro) {
						super.onFail(erro);
						disConnect();
						if (callback != null) {
							callback.onFail(ErroCode.ERROMAP.get("readsendpowerderro"));
						}
					}
				});
			
			}

			@Override
			public void reTryConnect(int lasttimes) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onDisConnect(ErroCode errocode) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onManualDisConnect(ErroCode errocode) {

			}

			@Override
			public void onDatasRecive(BluetoothGattCharacteristic rxd_charact) {

			}
		});

		return (result.getCode() == 0);
	}

	// 发送AT指令
	public boolean sendATCMD(MTBLEDevice device, String pwd, final String cmd, final SendCmdCallBack callback) {
		ErroCode result = connect(device, pwd, 1, false, new CallBack() {

			@Override
			public void onConnect(ErroCode errocode) {
				if (errocode.getCode() != 0) {
					if (callback != null) {
						callback.onFail(ErroCode.ERROMAP.get("connnectfail"));
					}
					return;
				}
				
				addNewAction(new WriteCharactWithAckAction(atcmd_charact, atcmd_charact, cmd.getBytes(), new Option(1000)){

					@Override
					public void onReciveDatas(BluetoothGattCharacteristic characteristic, byte[] datas) {
						super.onReciveDatas(characteristic, datas);
						setStatues(ActionStatues.DONE);
						if(callback != null){
							callback.onSuccess(new String(datas));
						}
						disConnect();
					}

					@Override
					public void onFail(ErroCode erro) {
						super.onFail(erro);
						if(callback != null){
							callback.onFail(erro);
						}
						disConnect();
					}
					
				});

			}

			@Override
			public void reTryConnect(int lasttimes) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onDisConnect(ErroCode errocode) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onManualDisConnect(ErroCode errocode) {

			}

			@Override
			public void onDatasRecive(BluetoothGattCharacteristic rxd_charact) {

			}
		});
		
		return (result.getCode() == 0);
	}

	private CallBack callback;

	// 回调
	public static interface CallBack {
		public void onConnect(ErroCode errocode);

		public void reTryConnect(int lasttimes);

		public void onDisConnect(ErroCode errocode);

		public void onManualDisConnect(ErroCode errocode);

		public void onDatasRecive(BluetoothGattCharacteristic rxd_charact);
	}

	// 读取数据回调
	public static interface ReadInfsCallBack {
		public void onSuccess(MTBeaconInfModel[] deviceinf);

		public void onFail(ErroCode erro);
	}

	// 设置通用参数回调
	public static interface BaseCallBack {
		public void onSuccess();

		public void onFail(ErroCode erro);
	}

	// 发送命令回调
	public static interface SendCmdCallBack{
		public void onSuccess(String ackmsg);

		public void onFail(ErroCode erro);
	}
}
